
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using Xceed.Chart.Core;
using Xceed.Chart.Standard;
using Xceed.Chart.GraphicsCore;
using Xceed.Chart.Server;

using Swaf;
using Swaf.BizObj;
using Swaf.Gui;
using Swaf.Security;
using System.Collections.Generic;

namespace Syrinx.Gui.AspNet
{
	[ToolboxData("<{0}:XCeedChartBizObjListDisplay runat=server></{0}:XCeedChartBizObjListDisplay>")]
    public class XCeedChartBizObjListDisplay : WebControl, IBizObjListDisplay 
	{
		public enum ChartType { Pie, Line, MultiLine, Bar };
		public enum Labeling { LegendOnly, LabelsOnly, Both };

		protected static Color[] s_defaultColors = new Color[]
			{Color.Red, Color.Blue, Color.Green, Color.Yellow, Color.Orange, Color.Purple, Color.Goldenrod, 
			Color.Honeydew, Color.Khaki, Color.LightBlue, Color.Pink, Color.PaleVioletRed};
		protected static int s_defaultWidth = 10;
		protected static int s_defaultHeight = 10;

		protected IBizObjList m_list;
        protected List<IBizObjList> m_lstIBizObjList = new List<IBizObjList>();
		protected Chart m_chart;
		protected ChartServerControl m_chartServer;
		protected string m_headerTxt = "";
		protected string m_dataField = "";
		protected string m_displayField = "";
		protected Color[] m_colors = null;
		protected ChartType m_type = ChartType.Pie;
		protected Labeling m_labelType = Labeling.LegendOnly;
        protected int m_maxElements = -1;

        protected string m_dateField = "";
		//protected string m_fileName = null;


        protected double m_min=0.0;
        protected double m_max=0.0;
        protected double m_average = 0.0;


		static XCeedChartBizObjListDisplay()
		{
			if(Licenser.LicenseKey == null || Licenser.LicenseKey == "")
				Xceed.Chart.Server.Licenser.LicenseKey = "CHW40-AUHMM-CTYAK-3AAA";
		}

		protected string m_parentIds;
		protected BizProcWidgetType m_procWidgetType = BizProcWidgetType.list;
		public string ParentBizProcIds { get { return m_parentIds; } set { m_parentIds = value; } }
		public BizProcWidgetType BizProcWidgetType { get { return m_procWidgetType; } set { m_procWidgetType = value; } }

		//public string FileName
        //{
        //    get
        //    {
        //        if(m_fileName == null)
        //            m_fileName = string.Format("/charts/Xceed_{0}.png", Guid.NewGuid().ToString().Replace("-", ""));
        //            //m_fileName = string.Format("/charts/Xceed_{0}.png", "test");
        //        return m_fileName;
        //    }
        //}

		public ChartType DisplayType
		{
			get { return m_type; }
			set { m_type = value; }
		}

		public Labeling ChartLabel
		{
			get { return m_labelType; }
			set { m_labelType = value; }
		}

		public string DataValueField
		{
			get { return m_dataField; }
			set { m_dataField = value; }
		}

		public string DataTextField
		{
			get { return m_displayField; }
			set { m_displayField = value; }
		}

        public string DataDateField
        {
            get { return m_dateField; }
            set { m_dateField = value;}
        }

		public string Header
		{
			get { return m_headerTxt; }
			set { if(m_headerTxt!=null) m_headerTxt = value; }
		}

		public IBizObjList BizObjList
		{
			get { return m_list; }
			set { m_list = value; }
		}

		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);
		}

		protected void setupChart()
		{
			if (Width == 0)
				Width = s_defaultWidth;
			if (Height == 0)
				Height = s_defaultHeight;

			if (m_list != null)
			{
				m_chartServer = new ChartServerControl();
                // TODO: resovle dyanamic path
                m_chartServer.ServerConfiguration.GeneralSettings.TempDirectory = "~/charts";
				this.Controls.Add(m_chartServer); // control
				m_chartServer.Background.FrameType = FrameType.None;
				//ImageFrame imageFrame = m_chartServer.Background.ImageFrame;
				//imageFrame.Border.Width = 0;

                // make background transparent.
                m_chartServer.Settings.TransparentBackground = true;
                m_chartServer.Background.FillEffect = new FillEffect(Color.Transparent);

				m_chart = m_chartServer.Charts[0];

                m_chartServer.Width = Width;
				m_chartServer.Height = Height;

				if (m_labelType == Labeling.LegendOnly || m_labelType == Labeling.Both)
					m_chart.Width = 70;
				else
					m_chart.Width = 60;

				m_chart.Height = 60;
				
			
				ChartLabel header = m_chartServer.Labels.AddHeader(m_headerTxt);
				header.TextProps.Backplane.Visible = false;
				//header.TextProps.Shadow.Type = ShadowType.GaussianBlur;
				header.TextProps.HorzAlign = HorzAlign.Left;
				header.TextProps.VertAlign = VertAlign.Top;
				header.HorizontalMargin = 2;
				header.VerticalMargin = 2;

				switch (m_type)
				{
					case ChartType.Pie:
						setupPieChart();
						break;
					case ChartType.Line:
						setupLineChart();
						break;
					case ChartType.Bar:
						setupBarChart();
						break;
                    case ChartType.MultiLine:
                        setupMultiLineChart();
                        break;
				}
			}
        }

        #region IBizObjListDisplay implementation

        public void showBizObjs(IBizObjCursor list)
        {
            m_list = list.Source;
            if (m_type == ChartType.MultiLine)
            {
                m_lstIBizObjList.Add(m_list);
            }
            
        }

        public string MaxElements { get { return m_maxElements.ToString(); } set { m_maxElements = int.Parse(value); } }

        public void getSelectedBizObjs(IBizObjList selected)
        {
            //TODO: Implement this method
        }
		public void setSelectedBizObjs(IBizObjList selected)
		{
		}
        
        public string WidgetId { get { return this.UniqueID; } }

        public Privileges EditPrivilege
        {
            get
            {
                return Privileges.ReadOnly;
            }
            set
            { }
        }

        public IBizObj SelectedBizObj
        {
            get
            {
                // this is just a chart we dont need to return anything
                return null;
            }
            set {  }
        }
        
        public object SelectedBizObjKeyValue
        {
            get
            {
                return null;
            }
			set { } 
        }

		public virtual void updateBizObjs()
		{
			//Intentionally left blank. Chart is read only.
		}
		public virtual void refresh()
		{
		}

        public event Swaf.Gui.BizObjSelectedInfo BizObjSelected;
        public event Swaf.Gui.BizObjChanged BizObjUpdated;

        public event Swaf.Gui.BizObjChanged BizObjDeleted;

        public event Swaf.Gui.BizObjChanged BizObjAdded;
        #endregion



        protected Color[] setupChartSeries(Series series)
		{
			if (m_labelType == Labeling.LegendOnly || m_labelType == Labeling.Both)
				series.Legend.Mode = SeriesLegendMode.DataPoints;
			else
				series.Legend.Mode = SeriesLegendMode.None;

			if (m_labelType == Labeling.Both || m_labelType == Labeling.LabelsOnly)
				series.DataLabels.Format = "<percent> - <label>";
			else
				series.DataLabels.Format = "";
			series.Appearance.FillMode = AppearanceFillMode.Predefined;

			return (m_colors == null) ? s_defaultColors : m_colors;
		}

		protected void setupPieChart()
		{
			PieSeries series = (PieSeries)m_chart.Series.Add(SeriesType.Pie);
			Color[] colors = setupChartSeries(series);

			series.PieStyle = PieStyle.SmoothEdgePie;
			series.LabelMode = PieLabelMode.Spider;

			////m_Pie.PieStyle = (PieStyle)PieStyleDropDownList.SelectedIndex;
			////m_Pie.BeginAngle = BeginAngleDropDownList.SelectedIndex * 10;
			//m_Pie.TotalAngle = TotalAngleDropDownList.SelectedIndex * 10;
			//m_Pie.LabelMode = (PieLabelMode)PieLabelModeDropDownList.SelectedIndex;
			//m_Pie.DataLabels.ArrowLength = ArrowLengthDropDownList.SelectedIndex;
			//m_Pie.DataLabels.ArrowPointerLength = ArrowPointerLengthDropDownList.SelectedIndex;

			if (m_list.numElements == 1 && getValue(m_list[0]) == 0.0)
				return;
			int colorIndex = 0;
			foreach (IBizObj obj in m_list)
			{
				try
				{
					series.AddPie(getValue(obj), 0.0, getLabel(obj), new FillEffect(colors[colorIndex++]), new LineProperties());
					if (colorIndex >= colors.Length)
						colorIndex = 0;
				}
				catch { }
			}
		}

        


		protected void setupBarChart()
		{
			BarSeries series = (BarSeries)m_chart.Series.Add(SeriesType.Bar);
			Color[] colors = setupChartSeries(series);

			int colorIndex = 0;
			foreach (IBizObj obj in m_list)
			{
				try
				{
					series.Add(getValue(obj), obj.get(m_displayField).ToString(), new FillEffect(colors[colorIndex++]), new LineProperties());
					if (colorIndex >= colors.Length)
						colorIndex = 0;
				}
				catch { }
			}

		}


        protected void setupMultiLineChart()
        {
            int ictr = 0, colorIndex=0;
            DateTime dt;

            if (m_lstIBizObjList.Count > 0)
            {
                m_chart.Axis(StandardAxis.PrimaryX).SetMajorShowAtWall(ChartWallType.Back, true);
                m_chart.Axis(StandardAxis.PrimaryX).MajorGridLine.Pattern = LinePattern.Dot;
                m_chart.Axis(StandardAxis.PrimaryX).ScaleMode = AxisScaleMode.DateTime;
                m_chart.Axis(StandardAxis.PrimaryX).OuterTickLength = 1.5f;
                m_chart.Axis(StandardAxis.PrimaryX).MinorTickLength = 1;

                m_chart.Axis(StandardAxis.PrimaryX).ValueFormatting.Format = Xceed.Chart.Utilities.ValueFormat.Date;
                //m_chart.Axis(StandardAxis.PrimaryY).Ruler.PagingMode = RulerPagingMode.FixedPageSize; 

                foreach (IBizObjList entry in m_lstIBizObjList)
                {

                    LineSeries series = (LineSeries)m_chart.Series.Add(SeriesType.Line);
                    Color[] colors = setupChartSeries(series);

                    if (ictr == 0)
                        series.MultiLineMode = MultiLineMode.Series;
                    else
                        series.MultiLineMode = MultiLineMode.Overlaped;

                    series.Legend.Mode = SeriesLegendMode.None;
                    series.InflateMargins = false;
                    //series.Markers.Visible = true;
                    //series.Markers.Border.Color = colors[colorIndex];
                    //series.Markers.Style = PointStyle.Ellipse;
                    //series.Markers.Width = 0.7f;
                    //series.Markers.Height = 0.7f;
                    //series.Markers.AutoDepth = true;

                    series.LineBorder.Color = colors[colorIndex];
                    series.LineFillEffect.SetSolidColor(colors[colorIndex]);
                    series.Markers.FillEffect.SetSolidColor(colors[colorIndex]);
                    series.Markers.Border.Color = colors[colorIndex];
                    series.UseXValues = true;

                    series.DataLabels.Mode = DataLabelsMode.Every;
                    series.DataLabels.DrawEvery = entry.Count / 8;
                    series.DataLabels.Format = "<label>";

                    series.Interactivity.TooltipMode = SeriesTooltipMode.DataPoints;
                    // show a hand when over a pie slice
                    //series.Interactivity.CursorMode = SeriesCursorMode.Default;
                    //series.Interactivity.DefaultCursor = CursorType.Hand;
                    // TODO: normalize data
                    computeMinMax(entry);

                    foreach (IBizObj obj in entry)
                    {
                        double d = getValueFromMinMax(obj);
                        series.Values.Add(d);
                        series.Labels.Add(getValue(obj).ToString("0.00"));

                        dt = getDateValue(obj);

                        series.XValues.Add(dt.ToOADate());
                        
                        // add the tooltips for the image map
                        series.Interactivity.Tooltips.Add(getValue(obj).ToString("0.00") + " on " + dt.ToString());
                    }

                    colorIndex++;
                    if (colorIndex >= colors.Length)
                        colorIndex = 0;
                    ictr++;

                    // for image map
                    series.Appearance.FillMode = AppearanceFillMode.DataPoints;
                    HTMLImageMapResponse imageMap = new HTMLImageMapResponse();
                    m_chartServer.ServerConfiguration.DefaultResponse = imageMap;

                }

                // setup the date range.
                if (m_lstIBizObjList[0].Count > 0)
                {
                    dt = getDateValue(m_lstIBizObjList[0][0]);
                    m_chart.Axis(StandardAxis.PrimaryX).DateTimeScale.Min = dt.ToOADate();

                    dt = getDateValue(m_lstIBizObjList[0][m_lstIBizObjList.Count - 1]);
                    m_chart.Axis(StandardAxis.PrimaryX).DateTimeScale.Max = dt.ToOADate();
                }
            }
        }


        protected void computeMinMax(IBizObjList lst)
        {
            if (lst.Count > 1)
            {
                double tmp, accum=0.0;
                m_min = getValue(lst[0]);
                m_max = getValue(lst[0]);
                foreach (IBizObj obj in lst)
                {
                    tmp = getValue(obj);
                    if (tmp < m_min)
                        m_min = tmp;
                    if (tmp > m_max)
                        m_max = tmp;

                    accum += tmp;
                }
                m_average = accum / (double)lst.Count;
            }
        }

        protected double getValueFromMinMax(IBizObj obj)
        {
            double val = getValue(obj);
            return ((val-m_min) / (m_max - m_min)) *100;
        }

		protected void setupLineChart()
		{
			LineSeries series = (LineSeries)m_chart.Series.Add(SeriesType.Line);
            Color[] colors = setupChartSeries(series);

			int colorIndex = 0;
			foreach (IBizObj obj in m_list)
			{
				try
				{
                    series.Add(getValue(obj), obj.get(m_displayField).ToString(), new FillEffect(colors[colorIndex++]), new LineProperties());
					if (colorIndex >= colors.Length)
						colorIndex = 0;
				}
				catch { }
			}
		}

		protected string getLabel(IBizObj obj)
		{
			object x = obj.get(m_displayField);
			return (x != null) ? x.ToString() : "";
		}

		protected double getValue(IBizObj obj)
		{
			object x = obj.get(m_dataField);
			double d = Convert.ToDouble(x);
			return d;
		}

        protected DateTime getDateValue(IBizObj obj)
        {
            object x = obj.get(DataDateField); 
            DateTime dt = Convert.ToDateTime(x);
            return dt;
        }

		protected override void OnPreRender(EventArgs e)
		{
			base.OnPreRender(e);
            // this doesnt trigger at all.
            //if (m_chartServer != null)
            //    m_chartServer.ImageExport.SaveToImageFile(Page.Server.MapPath("~" + FileName), new Size((int)Width.Value, (int)Height.Value), PixelFormat.Format32bppPArgb, ImageFormat.Png, 70, false);
		}

		protected override void RenderContents(HtmlTextWriter output)
		{
			setupChart();
			string fname = "";
            if (m_chartServer != null)
            {
                //fname = FileName;

                foreach (Control c in this.Controls)
                {
                    int strt = output.InnerWriter.ToString().Length;
                    c.RenderControl(output);
                    int newLen = output.InnerWriter.ToString().Length;
                    if (strt > 0 && (newLen - strt) > 0)
                    {
                        // TODO: HACK must find way to get the absolute path of the image
                        m_outputBuffer.Append(output.InnerWriter.ToString().Substring(strt, newLen - strt));
                        m_outputBuffer = m_outputBuffer.Replace("src=\"charts/", "src=\"../../charts/");
                    }
                }


                //m_chartServer.ImageExport.SaveToImageFile(Page.Server.MapPath("~" + fname), new Size((int)Width.Value, (int)Height.Value), PixelFormat.Format32bppPArgb, ImageFormat.Png, 70, false);
                //output.Write("<img src='{0}'/>", fname);
            }
		}

        protected StringBuilder m_outputBuffer = new StringBuilder();

        public string OutputBuffer
        {
            get
            {
                return m_outputBuffer.ToString();
            }
        }
	}
}
